package dian.qing.li.demo.security.utils;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.MediaTypeExpression;
import org.springframework.web.servlet.mvc.condition.NameValueExpression;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Spring容器工具类
 *
 * @Author: liqingdian
 */
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    /**
     * 赋值上下文
     *
     * @Author: liqingdian
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (this.applicationContext == null) {
            this.applicationContext = applicationContext;
        }
    }

    /**
     * 获取上下文
     *
     * @Author: liqingdian
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 根据名称获取spring容器内实例
     *
     * @param name 名称
     * @Author: liqingdian
     */
    public static Object getBean(String name) {
        Object bean = getApplicationContext().getBean(name);
        return bean;
    }

    /**
     * 根据类型获取spring容器内实例
     *
     * @param clazz 类型
     * @Author: liqingdian
     */
    public static <T> T getBean(Class<T> clazz) {
        T bean = getApplicationContext().getBean(clazz);
        return bean;
    }

    /**
     * 根据名称，类型获取spring容器内实例
     *
     * @param name  名称
     * @param clazz 类型
     * @Author: liqingdian
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        T bean = getApplicationContext().getBean(name, clazz);
        return bean;
    }

    /**
     * @Author: liqingdian
     */
    public static List<Map<String, Object>> getRequestMappings() {
        RequestMappingHandlerMapping requestMapping = getBean(RequestMappingHandlerMapping.class);
        // 获取url与类和方法的对应信息
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMapping.getHandlerMethods();
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> data;
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : handlerMethods.entrySet()) {
            data = new HashMap<>();
            data.put("name", StringUtils.isNotBlank(m.getKey().getName()) ? m.getKey().getName() : m.getValue().getMethod().getName());
            data.put("reference", m.getValue().toString());
            data.put("value", m.getKey().getPatternsCondition().getPatterns());
            Set<String> method = m.getKey().getMethodsCondition().getMethods().stream().map(RequestMethod::toString).collect(Collectors.toSet());
            data.put("method", method);
            Set<String> consumes = m.getKey().getConsumesCondition().getConsumableMediaTypes().stream().map(MediaType::toString).collect(Collectors.toSet());
            data.put("consumes", consumes);
            Set<String> headers = m.getKey().getHeadersCondition().getExpressions().stream().map(NameValueExpression::getName).collect(Collectors.toSet());
            data.put("headers", headers);
            Set<String> params = m.getKey().getParamsCondition().getExpressions().stream().map(NameValueExpression::getName).collect(Collectors.toSet());
            data.put("params", params);
            Set<String> produces = m.getKey().getProducesCondition().getExpressions().stream().map(MediaTypeExpression::toString).collect(Collectors.toSet());
            data.put("produces", produces);
            list.add(data);
        }
        return list;
    }
}
